<template>
  <div class="comments-wrap">
    <div class="comments-top">
      <div class="comments-top-left">
        <span v-if="count === 0">暂无{{ commentName }}</span>
        <span v-else>
          <span style="margin: 0 1px;">{{ count }}</span>
          条{{ commentName }}
        </span>
      </div>
    </div>
    <div class="comments-panel">
      <div class="gituser-wrap">
        <div class="avatar-wrap">
          <!-- eslint-disable-next-line vue/no-v-html -->
          <div v-if="getAvatar()" class="avatar" v-html="getAvatar()" />
          <div v-else class="default-avatar" />
        </div>
        <div class="editor-wrap">
          <div class="form-wrap">
            <a-form :form="form">
              <a-row>
                <a-col :xs="24" :sm="24" :md="11">
                  <a-form-item>
                    <a-input
                      v-decorator="['username', usernameOpts]"
                      placeholder="你的昵称"
                      allow-clear
                      class="username-input"
                      :disabled="!!$auth.user"
                    >
                      <template slot="addonBefore">
                        <font-awesome-icon :icon="['far', 'user']" />
                      </template>
                    </a-input>
                  </a-form-item>
                </a-col>
                <a-col :xs="24" :sm="24" :md="{ span: 11, offset: 2 }">
                  <a-form-item>
                    <a-input
                      v-decorator="['website', websiteOpts]"
                      placeholder="昵称链接"
                      allow-clear
                    >
                      <template slot="addonBefore">
                        <font-awesome-icon :icon="['fas', 'link']" />
                      </template>
                    </a-input>
                  </a-form-item>
                </a-col>
              </a-row>
            </a-form>
          </div>
          <client-only>
            <editor
              ref="editor"
              height="150px"
              preview-style="tab"
              :options="editorOptions"
              @load="onEditorLoad"
            />
          </client-only>
          <div class="comment-btn-wrap">
            <a-tooltip>
              <template slot="title">
                打开Markdown语法速查
              </template>
              <a @click="mcsShow = true">
                <font-awesome-icon
                  :icon="['fab', 'markdown']"
                  style="font-size: 14px"
                />
                <span>支持Markdown语法</span>
              </a>
            </a-tooltip>
            <a-button type="primary" @click="postComment">
              <span>发表{{ commentName }}</span>
            </a-button>
          </div>
        </div>
      </div>
      <div class="comment-list">
        <ul>
          <li v-for="comment in comments" :key="comment._id" class="comment-li">
            <comment-item
              :comment="comment"
              :avatar="getAvatar(comment.username)"
              @referenceReply="referenceReply"
            />
          </li>
        </ul>
        <div v-if="hasNext" class="btn-next-wrap">
          <a-button size="large" @click="loadNext">
            查看更多
          </a-button>
        </div>
      </div>
    </div>

    <a-modal v-model="mcsShow" title="Markdown 语法速查" width="640px">
      <a-alert
        type="warning"
        message="评论及留言的内容不支持1-4级标题。"
        show-icon
        style="margin-bottom: 10px;"
      />
      <md-cheat-sheet />
      <div slot="footer">
        <a-button type="primary" @click="mcsShow = false">
          关闭
        </a-button>
      </div>
    </a-modal>
  </div>
</template>
<script lang="ts">
import Vue, { PropOptions } from 'vue';
import Avatars from '@dicebear/avatars';
import sprites from '@dicebear/avatars-jdenticon-sprites';
import 'lazysizes';
import CommentItem from '@/components/CommentItem.vue';
import MdCheatSheet from '@/components/MdCheatSheet.vue';
import { IComment } from '@/types/schema';
import { IResp } from '@/types';
import codeSyntaxHighlight from '@toast-ui/editor-plugin-code-syntax-highlight';
import hljs from 'highlight.js';
import editorEmojiPlugin from '../static/editor-emoji-plugin';
export default Vue.extend({
  components: {
    CommentItem,
    MdCheatSheet
  },
  props: {
    from: {
      type: Number,
      default: 1
    } as PropOptions<1 | 2>,
    articleId: {
      type: String,
      default: ''
    } as PropOptions<string>
  },
  data () {
    return {
      comments: [] as Array<IComment>,
      page: 1,
      pageSize: this.$store.state.settings.commentPageSize,
      mcsShow: false,
      isLoading: false,
      count: 0,
      hasNext: false,
      usernameOpts: {
        rules: [
          {
            required: true,
            message: '昵称不能为空！'
          },
          {
            min: 3,
            message: '昵称太短了！'
          },
          {
            max: 20,
            message: '昵称太长了！'
          }
        ]
      },
      websiteOpts: {
        rules: [
          {
            pattern: /^http/,
            message: '链接必须以http开头！'
          }
        ]
      }
    };
  },
  computed: {
    form (): any {
      return this.$form.createForm(this);
    },
    isGuestbook (): boolean {
      return this.from === 1;
    },
    commentName (): string {
      return this.isGuestbook ? '留言' : '评论';
    },
    editorOptions (): object {
      return {
        hideModeSwitch: true,
        usageStatistics: false,
        language: 'zh-CN',
        placeholder: `输入${this.commentName}内容`,
        previewHighlight: false,
        toolbarItems: [
          'bold',
          'italic',
          'strike',
          'divider',
          'hr',
          'quote',
          'divider',
          'ul',
          'ol',
          'task',
          'divider',
          'image',
          'table',
          'link',
          'divider',
          'code',
          'codeblock'
        ],
        hooks: {
          addImageBlobHook: (this as any).onAddImageBlob
        },
        plugins: [[codeSyntaxHighlight, { hljs }], [editorEmojiPlugin, { index: 14 }]]
      };
    }
  },
  created () {
    this.getComments();
  },
  mounted () {
    const userInfo = localStorage.getItem('commentUserInfo');
    if (userInfo) {
      try {
        const user = JSON.parse(userInfo);
        this.form.setFieldsValue(user);
      } catch (err) {}
    }
    if (this.$auth.user) {
      this.form.setFieldsValue({
        username: 'Admin'
      });
    }
  },
  methods: {
    async getComments () {
      this.isLoading = true;
      const { code, data }: IResp = await this.$axios.$get(
        `/api/${this.isGuestbook ? 'guestbook' : 'comments'}`,
        {
          params: {
            articleId: this.articleId,
            pageIndex: this.page,
            pageSize: this.pageSize
          }
        }
      );

      if (code === 1) {
        this.comments.push(...data.comments);
        this.hasNext = data.hasNext;
        this.count = data.count;
      }
      this.isLoading = false;
    },
    postComment () {
      this.form.validateFieldsAndScroll(async (error, values) => {
        if (!error) {
          const content = (this.$refs.editor as any)
            .invoke('getMarkdown')
            .trim();
          if (!content) {
            (this.$refs.editor as any).invoke('focus');
            return;
          }
          const { code, data, message } = await this.$axios.$post(
            `/api/${this.isGuestbook ? 'guestbook' : 'comment'}`,
            {
              articleId: this.articleId,
              content,
              ...values
            }
          );
          if (code === 1) {
            this.comments.unshift(data.comment);
            this.count++;
            (this.$refs.editor as any).invoke('setMarkdown', '');
          } else {
            this.$message.error(message || `${this.commentName}失败`);
          }
          localStorage.setItem('commentUserInfo', JSON.stringify(values));
        }
      });
    },

    onAddImageBlob (blob, callback) {
      if (process.client && blob) {
        const formData = new FormData();
        formData.append('file', blob);
        this.$axios.$post('/api/uploadImage', formData).then(resp => {
          if (resp.code === 1) {
            callback(resp.data.url, '');
          } else {
            console.error(resp.message);
            this.$message.error(resp.message);
          }
        });
      }
    },

    onEditorLoad () {
      (document.querySelector(
        '.gituser-wrap .comment-btn-wrap'
      ) as HTMLElement).style.display = 'flex';
    },

    referenceReply ({ username, content }) {
      let refText = content.replace(/^.*(\n+|$)/gm, text => '> ' + text);
      refText = `@${username}\n` + refText + '\n\n';
      (this.$refs.editor as any).invoke('setMarkdown', refText);
      const editorComp = this.$refs.editor as any;
      editorComp.invoke('focus');

      if (this.isGuestbook) {
        setTimeout(() => {
          window.scrollTo(0, 0);
        }, 0);
      } else {
        editorComp.$el.scrollIntoViewIfNeeded();
      }
    },

    loadNext () {
      this.page++;
      this.getComments();
    },
    getAvatar (username: string | undefined) {
      if (!username) {
        username = this.form.getFieldValue('username');
      }
      if (!username) {
        return '';
      }
      return new Avatars(sprites).create(username);
    }
  }
});
</script>
<style scoped>
.comment-btn-wrap {
  display: flex;
  justify-content: space-between;
  background: #fff;
  border-color: #e5e5e5;
  border-style: solid;
  border-width: 0 1px 1px;
  align-items: center;
  padding: 6px 10px;
  border-bottom-left-radius: 4px;
  border-bottom-right-radius: 4px;
  user-select: none;
  display: none;
}

.comment-btn-wrap div {
  font-size: 12px;
  color: #666;
}

.comments-top {
  display: flex;
  justify-content: space-between;
  margin-bottom: 15px;
}

.gituser-wrap {
  display: flex;
  padding-bottom: 20px;
  border-bottom: 1px solid #eee;
}

.avatar-wrap {
  width: 50px;
  height: 50px;
  border-radius: 4px;
  overflow: hidden;
  flex: none;
  margin-right: 16px;
  border: 1px solid #ddd;
  padding: 3px;
}

.default-avatar {
  height: 100%;
  background: url()
    center no-repeat #ccc;
  background-size: 30px;
  border-radius: 3px;
}

.editor-wrap {
  flex: auto;
}

.comments-panel {
  background: #fff;
  border-radius: 5px;
  padding: 20px;
}

.comments-wrap {
  margin-top: 20px;
}

.comment-list {
  margin-left: 56px;
  margin-top: 20px;
}

.comments-top-left {
  font-size: 16px;
  font-weight: 600;
}

.comments-top-right {
  font-size: 14px;
}

.btn-next-wrap {
  margin-left: -56px;
  margin-top: 25px;
}

.btn-next-wrap button {
  width: 100%;
  font-size: 15px;
}

.lazyload,
.lazyloading {
  opacity: 0;
}

.lazyloaded {
  opacity: 1;
}

.editor-wrap .ant-form-inline .ant-form-item-with-help {
  margin-bottom: 5px;
}

.username-input input {
  font-weight: 500;
}

.form-wrap .ant-form-item {
  margin-bottom: 10px;
}

@media (max-width: 576px) {
  .avatar-wrap {
    display: none;
  }

  .comment-list {
    margin-left: 0;
  }

  .comments-top {
    margin-left: 20px;
    margin-top: -10px;
  }

  .comments-panel {
    border-radius: 0;
  }
}
</style>
<style>
.comments-wrap .avatar {
  height: 100%;
  user-select: none;
  transition: transform 0.5s, opacity 1.5s;
}

.comments-wrap .avatar:hover {
  transform: scale(1.3);
}

.comments-wrap .tui-editor-contents img {
  max-height: 150px;
}
</style>
